import copy

import numpy as np
import numpy as py
from pydeck.data_utils.binary_transfer import array_to_binary
from streamlit import rerun

SBox=np.array([['9','4','A','B'],['D','1','8','5'],['6','2','0','3'],['C','E','F','7']])#S盒
RSBox=np.array([['A','5','9','B'],['1','7','8','F'],['6','0','2','3'],['C','4','D','E']])#逆S盒

def Ak(a,k):#密钥加,待处理a和密钥k为半字节矩阵
    r00 = np.array([x ^ y for x, y in zip(a[0, 0:4], k[0, 0:4])])
    r01 = np.array([x ^ y for x, y in zip(a[0, 4:8], k[0, 4:8])])
    r10 = np.array([x ^ y for x, y in zip(a[1, 0:4], k[1, 0:4])])
    r11 = np.array([x ^ y for x, y in zip(a[1, 4:8], k[1, 4:8])])
    r=np.array([np.hstack((r00,r01)),
                np.hstack((r10,r11))])
    return r

def NS(a,b):#半字节代替，a为半字节矩阵,b为1则为正替代，b为-1则为逆替代
    # SBox=np.array([['9','4','A','B'],['D','1','8','5'],['6','2','0','3'],['C','E','F','7']])#S盒
    # RSBox=np.array([['A','5','9','B'],['1','7','8','F'],['6','0','2','3'],['C','4','D','E']])#逆S盒
    match b:
        case 1:
            Box=SBox#替代
        case -1:
            Box=RSBox#逆替代
    # print(a[0, 0:2])
    # print('ttt')
    # print(a)
    a00 = hToA(Box[AToI(a[0, 0:2])][AToI(a[0, 2:4])])
    a01 = hToA(Box[AToI(a[0, 4:6])][AToI(a[0, 6:8])])
    a10 = hToA(Box[AToI(a[1, 0:2])][AToI(a[1, 2:4])])
    a11 = hToA(Box[AToI(a[1, 4:6])][AToI(a[1, 6:8])])
    a=np.array([np.hstack((a00,a01)),
                np.hstack((a10,a11))])
    return a

def hToA(a):#十六进制转二进制数组
    b = bin(int(a, 16))[2:].zfill(4)#转为四字节二进制
    c = np.array([int(bit) for bit in b])#转为数组
    return c
def iToA(a):
    b = bin(int(a))[2:].zfill(8)  # 转为八字节二进制
    c = np.array([int(bit) for bit in b])  # 转为数组
    return c
def iToA16(a):
    b = bin(int(a))[2:].zfill(16)  # 转为八字节二进制
    c = np.array([int(bit) for bit in b])  # 转为数组
    return c
def AToI(a):#二进制数组转整型
    b=''.join(str(bit) for bit in a)
    c=int(b,2)
    return c

def SR(a):#行移位，正、逆一致,a为半字节矩阵
    b=a.copy()
    b[1,0:4]=a[1,4:8]
    b[1,4:8]=a[1,0:4]
    return b

def MC(a):#列混淆，输入半字节矩阵
    #将半字节矩阵转化为一维数组，便于计算
    b = np.zeros(16, dtype=int)
    for i in range(0, 16):
        if 0 <= i < 4:
            b[i] = a[0][i]
        if 4 <= i < 8:
            b[i] = a[1][i - 4]
        if 8 <= i < 12:
            b[i] = a[0][i - 4]
        if 12 <= i < 16:
            b[i] = a[1][i - 8]
    # 公式源于附件D.2
    r00 = np.array([b[0] ^ b[6], b[1] ^ b[4] ^ b[7], b[2] ^ b[4] ^ b[5], b[3] ^ b[5]])
    r10 = np.array([b[2] ^ b[4], b[0] ^ b[3] ^ b[5], b[0] ^ b[1] ^ b[6], b[1] ^ b[7]])
    r01 = np.array([b[8] ^ b[14], b[9] ^ b[12] ^ b[15], b[10] ^ b[12] ^ b[13], b[11] ^ b[13]])
    r11 = np.array([b[10] ^ b[12], b[8] ^ b[11] ^ b[13], b[8] ^ b[9] ^ b[14], b[9] ^ b[15]])
    # 组合为半字节矩阵
    r = np.array([np.hstack((r00 , r01)),
                  np.hstack((r10 , r11))])

    return r
def IMC(a):#逆列混淆，输入半字节矩阵，返回半字节矩阵
    #待补充

    flag=0
    inp = ['','','','','']
    a = a.astype(str)

    b = np.zeros(5, dtype=int)
    for i in range(0, 16):
            if 0 <= i < 4:
                inp[1]=inp[1]+(a[0][i])
            if 4 <= i < 8:
                inp[2]=inp[2]+(a[1][i - 4])
            if 8 <= i < 12:
                inp[3]=inp[3]+(a[0][i - 4])
            if 12 <= i < 16:
                inp[4]=inp[4]+(a[1][i - 8])

    r00 = gf2_add(gf2_multiply('9',inp[1]),gf2_multiply('2',inp[2]))
    r10 = gf2_add(gf2_multiply('2',inp[1]),gf2_multiply('9',inp[2]))
    r01 = gf2_add(gf2_multiply('9',inp[3]),gf2_multiply('2',inp[4]))
    r11 = gf2_add(gf2_multiply('2',inp[3]),gf2_multiply('9',inp[4]))
    r00 = list(r00)
    r10 = list(r10)
    r01 = list(r01)
    r11 = list(r11)

    # 数字字符列表
    # 使用列表推导式转换为整数
    r00 = [int(num) for num in r00]
    r10 = [int(num) for num in r10]
    r01 = [int(num) for num in r01]
    r11 = [int(num) for num in r11]

    r = np.array([np.hstack((r00 , r01)),
                  np.hstack((r10 , r11))])
    return r

def gf2_add(xo, xp):
    num1 = int(xo, 2)
    num2 = int(xp, 2)
    return bin(num1 ^ num2)[2:].zfill(4)  # 进行异或并返回4位的二进制字符串

def gf2_multiply(x1, x2):
    # 将字符串转换为整数
    chengfa2 = {'0':0,
                '1':2,
                '2':4,
                '3':6,
                '4':8,
                '5':10,
                '6':12,
                '7':14,
                '8':3,
                '9':1,
                '10':7,
                '11':5,
                '12':11,
                '13':9,
                '14':15,
                '15':13}
    chengfa9 = {'0':0,
                '1':9,
                '2':1,
                '3':8,
                '4':2,
                '5':11,
                '6':3,
                '7':10,
                '8':4,
                '9':13,
                '10':5,
                '11':12,
                '12':6,
                '13':15,
                '14':7,
                '15':14}
    num2 = int(x2, 2)
    if x1 == '2':
        ans = chengfa2[str(num2)]
    if x1 == '9':
        ans = chengfa9[str(num2)]
    outans = bin(int(ans))[2:].zfill(4)
    return outans

def gFunction(w,r):#g函数，用于密钥拓展,w为一个字节,r为RCON
    if r==1:
        RCON=np.array([1,0,0,0,0,0,0,0])
    if r==2:
        RCON=np.array([0,0,1,1,0,0,0,0])
    n0=w[0:4]
    n1=w[4:8]
    #S盒替换
    n0 = hToA(SBox[AToI(n0[0:2])][AToI(n0[2:4])])
    n1 = hToA(SBox[AToI(n1[0:2])][AToI(n1[2:4])])
    #交换并组合
    #print(n0,n1)
    n=np.hstack((n1,n0))
    #与RCON异或
    w1=AToI(n)^AToI(RCON)
    #转为二进制数组
    w2=bin(int(w1))[2:].zfill(8)
    wOut=np.array([bit for bit in w2])
    return wOut

def expandKey(k):#密钥拓展,输入16位密钥
    w0=k[0:8]
    w1=k[8:16]
    #公式源于附录D.3
    w2=iToA(AToI(w0)^AToI(gFunction(w1,1)))
    w3=iToA(AToI(w2)^AToI(w1))
    w4=iToA(AToI(w2)^AToI(gFunction(w3,2)))
    w5=iToA(AToI(w4)^AToI(w3))
    return w0,w1,w2,w3,w4,w5

def encipher(a,k):#加密，a为16位明文(一维二进制数组，元素均为整数1或0)，k为16位密钥(形式同a)，输出同格式
    w0,w1,w2,w3,w4,w5=expandKey(k)
    aSub1=a[0:8]
    aSub2=a[8:16]
    print(aSub1,aSub2)
    a0=np.array([aSub1,aSub2])#转化为半字节矩阵
    w01=np.array([w0,w1])
    print(a0)
    a1=Ak(a0,w01)#轮密钥加
    a2=NS(a1,1)#半字节替代
    a3=SR(a2)#行位移
    a4=MC(a3)#列混淆
    w23=np.array([w2,w3])
    a5=Ak(a4,w23)#轮密钥加
    a6=NS(a5,1)#半字节替代
    a7=SR(a6)#行位移
    w45=np.array([w4,w5])
    a8=Ak(a7,w45)#轮密钥加
    a8=np.reshape(a8,16)#转换形状为一维
    return a8

def decipher(a,k):#解密，a为16位密文(一维二进制数组，元素均为整数1或0)，k为16位密钥(形式同a)，输出同格式
    w0, w1, w2, w3, w4, w5 = expandKey(k)
    w01 = np.array([w0, w1])
    w23 = np.array([w2, w3])
    w45 = np.array([w4, w5])
    aSub1 = a[0:8]
    aSub2 = a[8:16]
    a0 = np.array([aSub1, aSub2])  # 转化为半字节矩阵
    a1 = Ak(a0, w45)  # 轮密钥加
    a2=SR(a1)#逆行移位
    a3=NS(a2,-1)#逆半字节替代
    a4 = Ak(a3, w23)  # 轮密钥加
    a5=IMC(a4)#逆列混淆
    a6=SR(a5)#逆行移位
    a7=NS(a6,-1)#逆半字节替代
    a8=Ak(a7,w01)#轮密钥加
    a8 = np.reshape(a8, 16)  # 转换形状为一维
    return a8

def Bit16process(mode,inputmode,wenben,miyao): #inputmode 为ASCIImode时启用文字编码输入，否则默认二进制
    if inputmode == 'ASCIImode' :
        wenben = ''.join(format(ord(char), '08b') for char in wenben)
        wenben = [int(char) for char in wenben]
    if mode == 'cipher':
        outans = encipher(wenben,miyao)
    if mode == 'decipher' :
        outans = decipher(wenben,miyao)
    if inputmode == 'ASCIImode' :
        outans = outans.tolist()
        outans = binary_list_to_string(outans)
    return outans

def Bit32process(mode,inputmode,wenben,miyao): # 32位 双重加密
    if mode == 'cipher' :
        Miyao_1 = miyao[:16]  # 前16个元素
        Miyao_2 = miyao[16:]  # 后16个元素
    if mode == 'decipher' :
        Miyao_2 = miyao[:16]  # 前16个元素
        Miyao_1 = miyao[16:]  # 后16个元素
    processkey = Bit16process(mode,inputmode,wenben,Miyao_1)
    ans = Bit16process(mode,inputmode,processkey,Miyao_2)
    return ans

def Bit32ProcessTriple(mode,inputmode,wenben,miyao):
    miyao_1 = miyao[:16]  # 前16个元素
    miyao_2 = miyao[16:]  # 后16个元素
    processkey = Bit16process(mode,inputmode,wenben,miyao_1)
    processkeySec = Bit16process(mode,inputmode,processkey,miyao_2)
    ans = Bit16process(mode,inputmode,processkeySec,miyao_1)
    return ans

def CrackDown(textcipher,textdecipher,mode):##!!!!返回的k1+k2的列表是十进制
    midcipher = []
    key = []
    for i in range (0,32768):
        probkey = iToA16(i)
        probkey = probkey.tolist()
        k = Bit16process('cipher',mode,textcipher,probkey)
        if mode == 'default':
            k=k.tolist()
        midcipher.append(k)
    middecipher = []
    for i in range (0,32768):
        probkey = iToA16(i)
        probkey = probkey.tolist()
        k = Bit16process('decipher',mode,textdecipher,probkey)
        if mode == 'default':
            k=k.tolist()
        middecipher.append(k)
    for i in range(0,32768):
        for j in range(0,32768):
            if midcipher[i] == middecipher[j]:
                key.append([i,j])
    return key
def InCommon(key1,key2):
    common_sublists = [sublist for sublist in key1 if sublist in key2]
    return common_sublists

def TotalCrackDown(mode,t1,t2):  ##!!!!返回的k1+k2的列表是十进制
    textcipher=t1
    textdecipher=t2
    Times=1
    print('cracking')
    keyremain=CrackDown(textcipher,textdecipher,mode)
    for i in range(1,Times):
        l = []
        textcipher = input('now')
        textdecipher = input()
        mode = input()
        print("cracking")
        keynew = []
        for row_index,row in enumerate(keyremain):
            probkey1 = iToA16(keyremain[row_index][0])
            probkey1 = probkey1.tolist()
            k1 = Bit16process('cipher', mode, textcipher, probkey1)
            if mode == 'default':
                k1 = k1.tolist()
            probkey2 = iToA16(keyremain[row_index][1])
            probkey2 = probkey2.tolist()
            k2 = Bit16process('decipher', mode, textdecipher, probkey2)
            if mode == 'default':
                k2 = k2.tolist()
            if k1 == k2:
                keynew.append([probkey1,probkey2])
        del keyremain
        keyremain = copy.deepcopy(keynew)
    return keyremain

def binary_list_to_string(binary_list):
    # 将每8位二进制位拆分为多个字符
    chars = []
    for i in range(0, len(binary_list), 8):
        binary_str = ''.join(str(bit) for bit in binary_list[i:i+8])
        chars.append(chr(int(binary_str, 2)))
    return ''.join(chars)
#测试代码
# a=np.array([0,1,0,0,1,1,1,0,1,0,0,1,1,0,0,1])#明文
# b=np.array([1,0,1,0,0,0,1,1,0,1,0,1,0,1,1,0])#密文
# k=np.array([0,0,1,1,1,0,0,1,0,1,0,0,1,1,0,0])#密钥
# prolongkey=np.array([0,0,1,1,1,0,0,1,0,1,0,0,1,1,0,1,0,1,0,0,0,1,1,0,1,0,1,0,1,1,0,1])

# ans=Bit16process('cipher','default',a,k)
# print(ans)
# ans=Bit16process('decipher','default',a,k)
# print(ans)
# print('ASCII:')
# ans=Bit16process('cipher','ASCIImode','SB',k)
# print(ans)
# ans=Bit16process('decipher','ASCIImode','§W',k)
# print(ans)
# print('32bit:')
# ans=Bit32process('cipher','default',a,prolongkey)
# print(ans)
# e=ans
# ans=Bit32process('decipher','default',e,prolongkey)
# print(ans)
# print('triple:')
# ans=Bit32ProcessTriple('cipher','default',a,prolongkey)
# print(ans)
# e=ans
# ans=Bit32ProcessTriple('decipher','default',e,prolongkey)
# print(ans)

# s=TotalCrackDown(2)
# print(s)
# print(CrackDown('SB','FK','ASCIImode'))
